import { ShaderMaterial, IShaderMaterialOptions } from '@babylonjs/core/Materials/shaderMaterial';
import { Color3 } from '@babylonjs/core/Maths/math.color';
import { Scene } from '@babylonjs/core/scene';

/**
 * 基础线材质参数对象
 * @param depthOffset 深度偏移值
 * @param dashSize 虚线段长度（与几何体属性保持一致）
 * @param gapSize 虚线空白长度（与几何体属性保持一致）
 * @param opacity 不透明度
 * @param dashed 是否为虚线
 * @param color 颜色
 * @param fillMode 填充模式（开放，闭合，间断线）
 */
interface IBasicLineMaterialOptions extends IShaderMaterialOptions {
    depthOffset?: number,
    dashSize?: number,
    gapSize?: number,
    opacity?: number,
    dashed?: boolean,
    color?: Color3,
    fillMode?: 4 | 5 | 6,
}


/**
 * 基础线（gl-line）材质
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 */
class BasicLineMaterial extends ShaderMaterial {

    private _depthOffset!: number;
    private _dashSize!: number;
    private _gapSize!: number;
    private _opacity!: number;
    private _dashed!: boolean;
    private _color!: Color3;

    constructor(name: string, scene: Scene, options?: Partial<IBasicLineMaterialOptions>) {
        super(name, scene, '', options);
        this.initialize(options);
    }

    /**
     * 设置是否为虚线
     */
    public set dashed(dashed: boolean) {
        this._dashed = dashed;
        this.setInt('dashed', dashed ? 1 : 0);
    }

    /**
     * 获取是否为虚线
     */
    public get dashed(): boolean {
        return this._dashed;
    }

    /**
     * 设置不透明度
     */
    public set opacity(opacity: number) {
        this._opacity = opacity;
        this.setFloat('opacity', opacity);
    }

    /**
     * 获取不透明度
     */
    public get opacity(): number {
        return this._opacity;
    }

    /**
     * 设置虚线空白长度
     */
    public set gapSize(size: number) {
        this._gapSize = size;
        this.setFloat('gapSize', size);
    }

    /**
     * 获取虚线空白长度
     */
    public get gapSize(): number {
        return this._gapSize;
    }

    /**
     * 设置虚线段长度
     */
    public set dashSize(size: number) {
        this._dashSize = size;
        this.setFloat('dashSize', size);
    }

    /**
     * 获取虚线段长度
     */
    public get dashSize(): number {
        return this._dashSize;
    }

    /**
     * 设置深度偏移
     */
    public set depthOffset(offset: number) {
        this._depthOffset = offset;
        this.setFloat('depthOffset', offset);
    }

    /**
     * 获取深度偏移
     */
    public get depthOffset(): number {
        return this._depthOffset;
    }

    /**
     * 设置颜色
     */
    public set color(color: Color3) {
        this._color = color;
        this.setColor3('color', color);
    }

    /**
     * 获取颜色
     */
    public get color(): Color3 {
        return this._color;
    }

    /**
     * 初始化
     * @param options 参数对象
     */
    private initialize(options?: Partial<IBasicLineMaterialOptions>): void {
        this.initializeVariable(options);
        this.initializeShader();
        this.initializeUniforms();
    }

    /**
     * 初始化变量值
     * @param options 参数对象
     */
    protected initializeVariable(options?: Partial<IBasicLineMaterialOptions>): void {
        const op = options || {};
        this._depthOffset = op.depthOffset || 0;
        this._dashSize = op.dashSize || 0.1;
        this._gapSize = op.gapSize || 0.1;
        this._opacity = op.opacity || 1;
        this._dashed = !!op.dashed;
        this._color = op.color || new Color3(1, 1, 1);
        this.fillMode = op.fillMode || ShaderMaterial.LineStripDrawMode;
        this.doNotSerialize = true;
    }

    /**
     * 设置uniform值
     */
    protected initializeUniforms(): void {
        this.options.attributes = ['position', 'lineDistance'];
        this.options.uniforms = ['worldView', 'projection',
            'depthOffset', 'dashSize', 'gapSize', 'opacity', 'dashed', 'color'];

        this.setFloat('depthOffset', this._depthOffset);
        this.setFloat('dashSize', this._dashSize);
        this.setFloat('gapSize', this._gapSize);
        this.setFloat('opacity', this._opacity);
        this.setInt('dashed', this._dashed ? 1 : 0);
        this.setColor3('color', this._color);

    }

    /**
     * 初始化顶点着色器和片元着色器
     */
    protected initializeShader(): void {
        this.shaderPath = {
            vertexSource: `
                precision highp float;
                attribute vec3 position;
                attribute float lineDistance;
                uniform mat4 worldView;
                uniform mat4 projection;
                uniform float depthOffset;
                varying float vDistance;
                void main(){
                    vec4 mvPosition=worldView*vec4(position,1.0);
                    vec4 pmvPosition=projection*mvPosition;
                    pmvPosition.z+=depthOffset;
                    vDistance=lineDistance;
                    gl_Position=pmvPosition;
                }
            `,
            fragmentSource: `
                precision highp float;
                uniform float dashSize; 
                uniform float gapSize;
                uniform float opacity; 
                uniform int dashed;
                uniform vec3 color;
                varying float vDistance;
                void main(){
                    vec4 col=vec4(color.rgb,opacity);
                    if(dashed==0){
                        gl_FragColor=col;
                    }else{
                        float dev=mod(vDistance,dashSize+gapSize);
                        if(dev>dashSize){
                            discard;
                        }
                        gl_FragColor=col;
                    }
                }
            `,
        };
    }

}


export { BasicLineMaterial };
export type { IBasicLineMaterialOptions };